{[j=20-/40/80!,o=95,a-]}			   { PasMat formatting options }
 
{$SETC AppleShareFriendly = FALSE}	   {set this to TRUE to save configuration to a resource
										file, FALSE saves it to the application's resources}

PROGRAM Events; 					   {a program to demonstrate how an application receives
										events under Juggler 6/30/87}

 {
   modified 8/1/87(v1.0B4):   Just call SystemTask iff GNE is being called
   Saves window positions (like a real "Juggler-friendly" app)
   modified 9/1/87 to fix bugs -- thanks CK!
 }

	USES
		{$PUSH}

		{$LOAD PasDump.dump}
		Memtypes,QuickDraw,OSIntf,ToolIntf,PackIntf,WLW {WritelnWindow};
		{$LOAD}
		{$POP}

		{$D+}
		{$R-}
		
	CONST
		TheAngle			= 15;	   {angle to paint in each time in dial-drawing routine}
		MaxChunk			= 360 DIV TheAngle;
		WNETrapNum			= $60;	   {trap number of WaitNextEvent}
		UnImplTrapNum		= $9F;	   {trap number of "unimplemented trap"}

		{Window IDs}
		FugitID 			= 128;
		InfoID				= 129;	   {resource IDs of our two windowettes}
		DebugID 			= 130;	   {resource ID of WIND template for debug window}
		AboutMeDLOG 		= 128;	   {resource ID of our about dialog}

		DebugWNum			= 1;	   {array indices to our windows}
		FugitWNum			= 2;
		InfoWNum			= 3;

		NumWindows			= InfoWNum; {FugitWind,InfoWind,DebugWind}

		{Menu IDs}
		MenuCount			= 3;	   {total number of menus}
		AppleID 			= 128;	   {resource IDs/menu IDs for Apple,File and Options menus}
		FileID				= 129;
		OptionID			= 130;

		AppleM				= 1;	   {index for each menu in myMenus (array of menu handles)}
		FileM				= 2;
		OptionM 			= 3;

		AboutMeItem 		= 1;	   {menu item number of about me}
		QuitItem			= 1;	   {menu item number of "quit" in file menu}
		ShowMouseItem		= 1;	   {menu item number of ShowMouseItem in options menu}

		ConfCreator 		= 'EVNT';  {creator bytes for this application}
		ConfResType 		= 'CnFG';  {resource type of configuration data in configuration
										file, registered with tech support}
		ConfResID			= 128;	   {resource ID... " " "}
		ConfigFNameStrID	= 128;	   {resource ID of configuration file name string}

		{low-memory globals that we MUST use}
		GrayRgnLowMemGlobal = $9EE;    {location of low-memory global for gray region -- this
										is the only way to get the correct region for multiple
										screens on the Mac II}
		MBarHeight			= $BAA;    {low-memory global location for mBarHeight}

	TYPE
		ELongPtr = ^Longint;
		EWordPtr = ^Integer;
		LongStuffType		= RECORD   {For type conversions}
								  CASE Integer OF
									  1:
										  (long: longint);
									  2:
										  (HiWrd,LoWrd: Integer);
									  3:
										  (HiByte,HiMidByte,LoMidByte,LoByte: SignedByte);
							  END;	   {LongStuffType}

		ConfigWindInfo		= RECORD
								  windTopLeft: Point;
								  height: Integer;
								  width: Integer;
							  END;	   {ConfigWindInfo}

		ConfigResType		= RECORD   {to write to configuration file}
								  grayRgnRect: Rect; {so we can keep track of the GrayRgn's
													  bbox}
								  configWindArray: ARRAY [1..NumWindows] OF ConfigWindInfo;
							  END;
		pConfigResType		= ^ConfigResType;
		hConfigResType		= ^pConfigResType;

	VAR
		MyMenus 		   : ARRAY [1..MenuCount] OF MenuHandle;
		MyEvent 		   : EventRecord;
		FugitWind		   : WindowPtr; {our window that will show the rotating dial}
		InfoWind		   : WindowPtr; {the window that will show status information}
		YieldTime		   : Integer;  {number of ticks to pass to WNE}
		SysEnv			   : SysEnvRec; {for SysEnvirons}
		WNEIsImplemented   : BOOLEAN;  {is WaitNextEvent implemented}
		Suspended		   : BOOLEAN;  {are we in the background?}
		Done			   : BOOLEAN;
		ThePat			   : Pattern;  {used for drawing the rotating dial}
		ArcRect 		   : Rect;	   { " " }
		Chunk			   : Integer;  { " " }
		PatIsBlack		   : BOOLEAN;  {we need this to flip patterns}
		WNERgn			   : RgnHandle; {cursor region to pass to WNE}
		InfoWindRgn 	   : RgnHandle; {rgn containing rect of InfoWind in global coords}
		AllButInfoWindRgn  : RgnHandle; {rgn containing everything but InfoWind rgn}
		ShowMouseMoved	   : BOOLEAN;  {whether to report on mouse moved events or not}
		MouseMovedMessage  : SignedByte; {we need this to check for mouse-moved events}
		PlusCursH		   : CursHandle; {cursor handle for the plus cursor}
		Err 			   : OSErr;    {general purpose error checker}
		WChanged		   : BOOLEAN;  {have any of our windows changed -- not used in this
										version}
SusPendCount: Integer;
{------------------------------------------------------------------------------------}

(* FUNCTION WaitNextEvent(eventMask: Integer; VAR theEvent: EventRecord; sleep: longint;
   mouseRgn: RgnHandle): BOOLEAN;
  INLINE $A860;
*)
		{the above is now in the MPW 2.0 interfaces}

		{------------------------------------------------------------------------------------}

PROCEDURE EvInitWW(r: Rect; wName: Str255);

CONST
	EvNewCentury = 34; {font Family of New Century SchoolBook}

	VAR
		WWFamily,WWSize: Integer;

	BEGIN {InitWW}
		WWInit(50,80);

		IF RealFont(EvNewCentury,10) THEN BEGIN
			WWFamily := EvNewCentury;
			WWSize := 10
		END
		ELSE BEGIN
			WWFamily := monaco;
			WWSize := 9
		END;
		WWNew(r,wName,false,true,WWFamily,WWSize);
		SetWRefCon(gDebugWindowPtr,0);    {clear out the refcon to show no change in configuration}
	END; {InitWW}

		{------------------------------------------------------------------------------------}

	PROCEDURE SetUpMenus;
	{set up menus and menu bar}

		VAR
			i				   : Integer;

		BEGIN
			MyMenus[AppleM] := GetMenu(AppleID); {read Apple menu from resource file}
			AddResMenu(MyMenus[AppleM],'DRVR'); {add desk accessory names to Apple menu}
			MyMenus[FileM] := GetMenu(FileID); {read file menu from resource file}
			MyMenus[OptionM] := GetMenu(OptionID); {read file menu from resource file}

			FOR i := 1 TO MenuCount DO InsertMenu(MyMenus[i],0); {install menus in menu bar}
			DrawMenuBar;			   {and draw menu bar}
		END;						   {of SetUpMenus}

	{------------------------------------------------------------------------------------}

	FUNCTION MenuBarHeight: Integer;   {returns the menu height, independent of ROM}

		CONST
			MHt64KROM			= 20;  {menu-bar height for 64K ROMs}

		BEGIN						   {MenuBarHeight}
			IF SysEnv.machineType < 0 THEN {64K ROM machine}
				MenuBarHeight := MHt64KROM
			ELSE
				MenuBarHeight := EWordPtr(MBarHeight)^; {get it from low-memory}
		END;						   {MenuBarHeight}

	{------------------------------------------------------------------------------------}

	PROCEDURE DoAbout;				   {display the About box}

		VAR
			aboutMeDialog	   : DialogPtr; {our dialog}
			screenWidth 	   : Integer;
			screenHeight	   : Integer;
			theItem 		   : Integer;

		BEGIN						   {DoAbout}
			{now we'll get our INVISIBLE dialog -- invisible so we can center it}
			aboutMeDialog := GetNewDialog(AboutMeDLOG,NIL,WindowPtr( - 1));

			{we'll need these for centering}
			screenWidth := ScreenBits.bounds.right - ScreenBits.bounds.left;
			screenHeight := ScreenBits.bounds.bottom - ScreenBits.bounds.top-MenuBarHeight;

			{let's center it (it's still invisible)}
			WITH aboutMeDialog^.portRect DO
				MoveWindow(aboutMeDialog,(screenWidth - (right - left)) DIV 2,(screenHeight -
						   (bottom - top)) DIV 2,TRUE); {center it}

			ShowWindow(aboutMeDialog); {make it visible}
			REPEAT
				ModalDialog(NIL,theItem); {this'll stop those pesky background tasks}
			UNTIL theItem = OK;
			DisposDialog(aboutMeDialog); {get rid of the about box dialog}
		END;						   {DoAbout}


	{------------------------------------------------------------------------------------}

	PROCEDURE FlipCursor;
	{we got a mouse-moved event, flip the cursor and assign the new region}
	{we only get mouse-moved events if we are the foreground app!}
	{WritelnWindow slows the cursor change in this example}

		BEGIN						   {FlipCursor}
			IF WNERgn = InfoWindRgn THEN BEGIN
				SetCursor(Arrow);	   {the cursor was in the InfoWind, it has moved out, set
										cursor to arrow}
				WNERgn := AllButInfoWindRgn; {flip the region}
			END
			ELSE BEGIN				   {the region was AllButInfoWindRgn}
				SetCursor(PlusCursH^^); {the cursor was not in the InfoWind, it moved in, set
										 cursor to plu}
				WNERgn := InfoWindRgn; {flip the region}
			END
		END;						   {FlipCursor}

	{------------------------------------------------------------------------------------}

	PROCEDURE GetMouseCursor;		   {this is called when we get a menu command to turn
										ShowMouseMoved on}

		VAR
			mousePt 		   : Point;

		BEGIN						   {GetMouseCursor}
			SetPort(InfoWind);
			GetMouse(mousePt);		   {we need to get the mouse here to see where we are when
										the command was issued}

			IF (PtInRect(mousePt,thePort^.portRect)) & (PlusCursH <> NIL) THEN BEGIN {we're in
					the InfoWind}
				SetCursor(PlusCursH^^); {set to plus cursor}
				WNERgn := InfoWindRgn; {we want to know when we move outside of InfoWind}
			END
			ELSE BEGIN				   {we're not in the InfoWind}
				SetCursor(Arrow);	   {set to arrow}
				WNERgn := AllButInfoWindRgn; {we want to know when we move into InfoWind}
			END;					   {ELSE}
		END;						   {GetMouseCursor}

	{------------------------------------------------------------------------------------}

	PROCEDURE DoCommand(mResult: longint; byKey: BOOLEAN);

		CONST
			menuTicks			= 5;   {number of ticks to Delay when a MenuKey is hit: 1/12
										sec.}

		VAR
			theItem,theMenu    : Integer;
			daName			   : Str255; {name of DA to launch}
			temp			   : Integer;
			svPort			   : GrafPtr;
			longStuff		   : LongStuffType;

		BEGIN						   {DoCommand}
			longStuff.long := mResult; {Oh how I HATE calling HiWord and LoWord! -- you could
										call it, though}
			theItem := longStuff.LoWrd; {extract the menu and item numbers}
			theMenu := longStuff.HiWrd;
			CASE theMenu OF 		   {which menu?}
				AppleID:
					IF theItem = AboutMeItem THEN
						DoAbout
					ELSE BEGIN		   {it's a DA - get its name and open it}
						GetPort(svPort); {save the port}
						GetItem(MyMenus[AppleM],theItem,daName);
						temp := OpenDeskAcc(daName);
						SetPort(svPort); {put us back in our port}
					END;			   {ELSE}
				FileID: 			   {only one item in the File menu}
					CASE theItem OF
						QuitItem:
							Done := TRUE;
					END;			   {mini-case statement}
				OptionID:			   {for now, only one item in the Options menu}
					CASE theItem OF
						ShowMouseItem: BEGIN {this item will be disabled if we don't have
											  WaitNextEvent}
							ShowMouseMoved := NOT (ShowMouseMoved); {this menu item toggles}
							CheckItem(MyMenus[OptionM],theItem,ShowMouseMoved); {check it
								accordingly}
							IF ShowMouseMoved THEN
								GetMouseCursor {find out which cursor and which region we need}
							ELSE BEGIN
								WNERgn := NIL; {pass NIL to WNE for no mouse tracking}
								SetCursor(Arrow); {no mouse tracking, set cursor to arrow}
							END;
						END;		   {CASE ShowMouseItem}
					END;			   {CASE}
			END;					   {menu case}
			IF byKey THEN Delay(menuTicks,longStuff.long); {Delay to show item was hit}
			HiliteMenu(0);
		END;						   {DoCommand}

	{------------------------------------------------------------------------------------}

	PROCEDURE UpdateWindow(theWindow: WindowPtr; theStr: Str255); {the port is set correctly by
																   the main event loop}

		VAR
			myStr			   : Str255;
			r				   : Rect;

		BEGIN						   {UpdateWindow}
			BeginUpdate(theWindow);
			IF theWindow = InfoWind THEN BEGIN
				SetRect(r,5,0,theWindow^.portRect.right,40); {Erase just the two info items}
				EraseRect(r);
				MoveTo(5,20);
				IF WNEIsImplemented THEN BEGIN {display yieldtime}
					NumToString(YieldTime,myStr);
					DrawString(myStr);
					DrawString(' ticks');
				END
				ELSE
					DrawString('no WNE'); {this is easy}

				MoveTo(5,40);		   {to show information about 4Gnd/BackGnd}
				IF Suspended THEN
					DrawString('BackGnd')
				ELSE
					DrawString('4Gnd')
			END
			ELSE IF theWindow = FugitWind THEN
				IF PatIsBlack THEN
					FillArc(ArcRect,0,Chunk * TheAngle,Black) {fill in from 0 with black}
				ELSE
					FillArc(ArcRect,0,(Chunk * TheAngle) - 360,Black); {fill back from 0 with
				black}

			EndUpdate(theWindow);
			writeln(theStr);		   {to debug window}
		END;						   {UpdateWindow}

	{------------------------------------------------------------------------------------}

	PROCEDURE CalculateWNECursRgns;    {called at startup time and whenever the InfoWind is
										dragged}

		VAR
			totalScreenRgn	   : RgnHandle; {used to figure out AllButInfoWindRgn}
			r				   : Rect; {utility rectangle}

		BEGIN						   {CalculateWNECursRgns}
			r := InfoWind^.portRect;
			WITH r DO BEGIN
				LocalToGlobal(TopLeft);
				LocalToGlobal(botRight);
			END;
			RectRgn(InfoWindRgn,r);    {this needs to be in global coords}

			{now we'll make a region that combines the gray region and screenBits.bounds}
			{so we are sure to get the menu bar (then we won't get mouse-moveds when}
			{we're in the menu bar)}

		   {there's probably a faster way of doing this, but this way will work with a variety}
			{of menu bar heights and multiple screens}

			totalScreenRgn := NewRgn;  {we'll need this for a short time, get rid of it when
										done}
			{union GrayRgn's bbox with screenBits.bounds}
			UnionRect(ScreenBits.bounds,(RgnHandle(ELongPtr(GrayRgnLowMemGlobal)^)^^.rgnBBox),
					  r);
			InsetRect(r, - 20, - 20);  {to handle single screen Macs}
			RectRgn(totalScreenRgn,r); {convert to a region}

			DiffRgn(totalScreenRgn,InfoWindRgn,AllButInfoWindRgn); {diff of (gray+screenBits)
																	and InfoWind}
			DisposeRgn(totalScreenRgn); {we're all done with this}
		END;						   {CalculateWNECursRgns}

	{------------------------------------------------------------------------------------}

	{$IFC AppleShareFriendly=TRUE}

	FUNCTION OpenConfigFile: Integer;  {opens the configuration file, returns 0 if the open
										fails}
{

In order to keep track of our windows' positions, so that the user can put them where
he/she wants them and they will come up that way the next time the app is run, we will
use a configuration file.  We do this in order to be server (AppleShare) friendly. We
could keep a resource in our application's resource fork, but that would cause problems if
the application were shared.  So, we call SysEnvirons to see where we should put the file
(SysEnv.sysVRefNum) and away we go -- both Juggler- and AppleShare-friendly

}

		VAR
			oldVol			   : Integer;
			myStrH			   : StringHandle;

		BEGIN						   {OpenConfigFile}
			OpenConfigFile := 0;	   {default to error}
			Err := GetVol(NIL,oldVol); {save off the old volume}
			Err := SetVol(NIL,SysEnv.sysVRefNum); {set to the folder containing currently open
												   system file}
			IF Err = noErr THEN BEGIN  {if we get an error here, OpenConfigFile is set to fail
										(0) at this point}
				myStrH := GetString(ConfigFNameStrID); {from our application's resource file}
				OpenConfigFile := OpenResFile(myStrH^^); {if someone's ResEdited our resource
														  away, tough!!}
				ReleaseResource(Handle(myStrH)); {all done with it}
			END;					   {IF err = noErr}
			Err := SetVol(NIL,oldVol); {restore default directory}
		END;						   {OpenConfigFile}

	{$ENDC}
	{------------------------------------------------------------------------------------}

	PROCEDURE WriteConfigInfo;		   {writes configuration info (window positions) to the
										configuration file}

		VAR
			configFileRef	   : Integer;
			myStrH			   : StringHandle;
			oldVol			   : Integer;
			myFndrInfo		   : FInfo;

		 {------------------------------------------------------------------------------------}

		PROCEDURE WriteConfigData(whichResFile: Integer); {routine to write the data out}

			VAR
				myConfig		   : ConfigResType;
				hResConfig		   : Handle;

		 {------------------------------------------------------------------------------------}

			PROCEDURE FillInWInfo(whichWind: WindowPtr; arrElem: Integer;
								  VAR Data: ConfigResType); {gets window coordinates}

				VAR
					oldPort 		   : GrafPtr;
					p				   : Point;

				BEGIN				   {FillInWInfo}
					GetPort(oldPort);
					SetPort(whichWind); {set port for the LocalToGlobal to follow}
					p := whichWind^.portRect.TopLeft;
					LocalToGlobal(p);  {change to global coordinates}
					WITH Data.configWindArray[arrElem],whichWind^.portRect DO BEGIN
						windTopLeft := p;
						width := right - left;
						height := bottom - top;
					END;			   {WITH}
					SetPort(oldPort);  {restore port}
				END;				   {FillInWInfo}

		 {------------------------------------------------------------------------------------}

			BEGIN					   {WriteConfigData}
				{at this point, we know the appropriate resource file exists and is open}
				hResConfig := GetResource(ConfResType,ConfResID); {get the CNFG resource}
				IF (hResConfig = NIL) | (HomeResFile(hResConfig) <> whichResFile) THEN BEGIN
					IF hResConfig <> NIL THEN ReleaseResource(hResConfig); {It's not ours}
					hResConfig := NewHandle(sizeOf(myConfig)); {we'll make one}
					AddResource(hResConfig,ConfResType,ConfResID,''); {make a new one}
				END;				   {IF}

				{fill in the record with the appropriate information}
				FillInWInfo(gDebugWindowPtr,DebugWNum,hConfigResType(hResConfig)^^);
				FillInWInfo(FugitWind,FugitWNum,hConfigResType(hResConfig)^^);
				FillInWInfo(InfoWind,InfoWNum,hConfigResType(hResConfig)^^);
				hConfigResType(hResConfig)^^.grayRgnRect := (RgnHandle(ELongPtr(
																	   GrayRgnLowMemGlobal)^)^^
															.rgnBBox);
				ChangedResource(hResConfig); {we want it changed!} {no reason to
																	ReleaseResource this guy}
			END;					   {WriteConfigData}

		{------------------------------------------------------------------------------------}

		BEGIN						   {WriteConfigInfo}
			{$IFC AppleShareFriendly = TRUE}
			writeln('writing config info to file');
			Err := GetVol(NIL,oldVol); {save default volume}
			Err := SetVol(NIL,SysEnv.sysVRefNum); {set to system folder}

			{strategy: create a resfile, if we get an error, just skip ahead to the open}

			myStrH := GetString(ConfigFNameStrID); {from our application's resource file}
			CreateResFile(myStrH^^);   {ignore the error, just check for errors on the open
										call below}

			{IF we created the file, we need to set up the Finder Info}
			IF ResError = noErr THEN BEGIN
				{GetFInfo won't move memory, so no need to lock myStrH}
				Err := GetFInfo(myStrH^^,SysEnv.sysVRefNum,myFndrInfo);
				IF Err = noErr THEN BEGIN
					WITH myFndrInfo DO BEGIN
						fdType := ConfResType;
						fdCreator := ConfCreator;
					END;			   {WITH}
					Err := SetFInfo(myStrH^^,SysEnv.sysVRefNum,myFndrInfo);
				END;				   {IF}
			END;					   {IF ResError...}
			ReleaseResource(Handle(myStrH)); {all done with this string}
			configFileRef := OpenConfigFile; {go ahead and try to open it}

			{$ENDC}
			{$IFC AppleShareFriendly=TRUE}
			IF configFileRef <> 0 THEN BEGIN {the file exists, write configuration data}
				WriteConfigData(configFileRef); {write the actual data}
				CloseResFile(configFileRef); {and close the resource file}
				Err := FlushVol(NIL,SysEnv.sysVRefNum); {flush the volume the config file's on}
			END 					   {IF configFileRef <> 0}
			ELSE;					   {do nothing, we just couldn't write it}
			Err := SetVol(NIL,oldVol); {restore default volume}
			{$ELSEC}				   {Duplicated code below}
			writeln('writing config info to resource');
			WriteConfigData(CurResFile);
			{$ENDC}
		END;						   {WriteConfigInfo}

	{------------------------------------------------------------------------------------}

	FUNCTION ReadConfigInfo(VAR wConfig: ConfigResType): BOOLEAN; {reads the info in the
																   configuration file}

		VAR
			configFileRef	   : Integer;
			myConf			   : hConfigResType;

		BEGIN						   {ReadConfigInfo}
			{$IFC AppleShareFriendly=TRUE}
			ReadConfigInfo := FALSE;   {start with this as a default}

			configFileRef := OpenConfigFile; {try to open it}
			IF configFileRef <> 0 THEN BEGIN {we got the file}
				{$ENDC}
				myConf := hConfigResType(GetResource(ConfResType,ConfResID));
				IF myConf <> NIL THEN BEGIN
					ReadConfigInfo := TRUE; {This is true}
					wConfig := myConf^^;
					{$IFC AppleShareFriendly=TRUE}
					CloseResFile(configFileRef); {all done, close the ResFile}
					{$ENDC}
				END;				   {IF}
				{$IFC AppleShareFriendly=TRUE}
			END;					   {IF configFileRef...}
			{$ENDC}
		END;						   {ReadConfigInfo}

	{------------------------------------------------------------------------------------}

	PROCEDURE Initialize;

		PROCEDURE SetUpWindows; 	   {Gets windows and puts them in the right places}

{
NOTE:  I use a very simplistic method to see if I can use the saved window positions.
This is just an example, so you shouldn't use this code.  All I check is to see if the
GrayRgn's BBox has changed, and if it has, I assume that the world has changed, so I revert
to the default window positions.  This is to handle the multiple screens on the Macintosh II.
Real programs, such as the Finder, save window positions in a much more intelligent fashion.
The next version of Events, will include a better technique for handling this.
}

			TYPE
				WindRSRC			= RECORD
										  bounds: Rect;
										  procID: Integer;
										  visible: BOOLEAN;
										  Filler: BOOLEAN; {otherwise Pascal will pack Visible
															and goAwayFlag}
										  goAwayFlag: BOOLEAN;
										  filler2: BOOLEAN;
										  refCon: longint;
										  wTitle: Str255;
									  END;
				pWindRSRC			= ^WindRSRC;
				hWindRSRC			= ^pWindRSRC;

			VAR
				hWIND			   : hWindRSRC;
				myConfig		   : ConfigResType;
				r				   : Rect;
				windTitle		   : Str255;

			BEGIN					   {SetUpWindows}

				{get our two invisible windows}
				FugitWind := GetNewWindow(FugitID,NIL,WindowPtr( - 1));
				InfoWind := GetNewWindow(InfoID,NIL,WindowPtr( - 1));
				hWIND := hWindRSRC(GetResource('WIND',DebugID)); {we'll need this to get the
																  title string from}
				{or, if no configuration data is around, we'll get the bounds from this}

				IF ReadConfigInfo(myConfig) & EqualRect(myConfig.grayRgnRect,
														(RgnHandle(ELongPtr(GrayRgnLowMemGlobal)
														^)^^.rgnBBox)) THEN BEGIN {we have a
						saved window configuration}
					WITH myConfig DO BEGIN
						{first, set up FugitWind}
						WITH configWindArray[FugitWNum] DO BEGIN
							MoveWindow(FugitWind,windTopLeft.h,windTopLeft.v,FALSE);
							SizeWindow(FugitWind,width,height,FALSE);
						END;
						{Now, the InfoWind}
						WITH configWindArray[InfoWNum] DO BEGIN
							MoveWindow(InfoWind,windTopLeft.h,windTopLeft.v,FALSE);
							SizeWindow(InfoWind,width,height,FALSE);
						END;		   {WITH}
						{now, set up the rectangle for the debug window}

						WITH configWindArray[DebugWNum] DO
							SetRect(r,windTopLeft.h,windTopLeft.v,windTopLeft.h + width,
									windTopLeft.v + height);
					END;			   {WITH MyConfig}
				END 				   {IF}
				ELSE BEGIN			   {we don't have the configuration details...}
					{or the grayRgn's bbox changed, use defaults}
					{set up WritelnWindow stuff}
					r := hWIND^^.bounds;
					r.bottom := ScreenBits.bounds.bottom - 60;
				END;

				windTitle := hWIND^^.wTitle; {get the title}
				ReleaseResource(Handle(hWIND)); {all done}
				EvInitWW(r,windTitle); {we assume that no one's mucked with our resources}

				UnloadSeg(@WWInit);    {unload this segment as well}

				ShowWindow(FugitWind); {show our two invisible windows}
				ShowWindow(InfoWind);
				SelectWindow(InfoWind); {bring this window to the front}
			END;					   {SetUpWindows}

		{------------------------------------------------------------------------------------}

		PROCEDURE _DataInit;
			EXTERNAL;				   {so we can unload it}

		{------------------------------------------------------------------------------------}

		BEGIN						   {Initialize}
			UnloadSeg(@_DataInit);	   {unload data initialization code before any allocations}
			MoreMasters; MoreMasters;  {get some master pointer blocks}
			MaxApplZone;			   {grow the heap}
			InitGraf(@thePort); 	   {standard Macintosh inits}
			InitFonts;
			FlushEvents(everyEvent,0);
			InitWindows;
			InitMenus;
			TEInit;
			InitDialogs(NIL);
			InitCursor;

			Err := SysEnvirons(1,SysEnv); {first version of SysEnvirons, we don't care about
										   the error}

			SetUpMenus; 			   {get our menus}
			SetUpWindows;			   {configure our windows}
			FlushEvents(everyEvent,0);

			{initialize variables for drawing routines}
			ThePat := Black;		   {draw with this to start}
			PatIsBlack := TRUE; 	   {start with a black pattern for drawing}
			SetRect(ArcRect,10,10,90,90);
			Chunk := 0;

			ShowMouseMoved := FALSE;   {don't show these initially}
			{Is WaitNextEvent implemented?}
			WNEIsImplemented := (SysEnv.machineType >= 0) & {>= 128K ROMs}
				(NGetTrapAddress(WNETrapNum,ToolTrap) <> NGetTrapAddress(UnImplTrapNum,ToolTrap));
			IF NOT WNEIsImplemented THEN {disable showmousemoved menu item}
				DisableItem(MyMenus[OptionM],ShowMouseItem);

			{now let's calculate all of our cursor regions}
			SetPort(InfoWind);
			InfoWindRgn := NewRgn;	   {we'll need this for the WNE cursor stuff}
			AllButInfoWindRgn := NewRgn; {we'll need this for the WNE cursor stuff}
			CalculateWNECursRgns;	   {calculate the cursor regions}
			WNERgn := NIL;			   {default to ShowMouseMoved = FALSE}

			MouseMovedMessage := $FA;  {high byte of event record message for mouse moved
										events}
			PlusCursH := GetCursor(plusCursor);
			IF PlusCursH <> NIL THEN HNoPurge(Handle(PlusCursH));

			YieldTime := 0; 		   {don't yield any time (Juggler 1.0B3 and later)}
			WChanged := FALSE;		   {nobody's changed yet}
			SusPendCount:= 0;
		END;						   {Initialize}

	{------------------------------------------------------------------------------------}

	PROCEDURE MainEventLoop;

		CONST
			quantum 			= 2;   {run for 2 ticks before yielding}
			cleanUpTime 		= 300; {clean up once every 5 seconds}

		VAR
			hasEvent		   : BOOLEAN;
			whichWindow 	   : WindowPtr;
			whichPart		   : Integer;
			theChar 		   : char;
			longStuff		   : LongStuffType; {for conversions}
			dragRect		   : Rect;
			cleanUpTicks	   : longint; {so we know when to call CompactMem}
			timerTicks,ourTime : longint; {this is all for the percentage stuff -- thanks JM}
			runTime,elapsedTime: longint;
			lastTickCount	   : longint;
			lastPercent 	   : longint;

		 {------------------------------------------------------------------------------------}

		PROCEDURE DrawRotatingDial(VAR currentPat: Pattern);

			VAR
				myTicks 		   : longint;

			BEGIN					   {DrawRotatingDial}
				{Now draw the rotating dial}
				SetPort(FugitWind);    {set to correct port}

				myTicks := TickCount;  {synch to VBL the poor man's way}
				REPEAT
				UNTIL TickCount <> myTicks;

				FillArc(ArcRect,Chunk * TheAngle,TheAngle,currentPat); {draw a chunk}
				Chunk := Chunk + 1;    {go to next chunk}
				IF Chunk >= MaxChunk THEN BEGIN {we're done, flip color, reset Chunk}
					Chunk := 0;
					IF PatIsBlack THEN
						currentPat := white
					ELSE
						currentPat := Black;
					PatIsBlack := NOT (PatIsBlack);
				END;				   {IF}
			END;					   {DrawRotatingDial}

		{------------------------------------------------------------------------------------}

		PROCEDURE DrawPercentage(runTim,eTime: longint; VAR lastPerct: longint);

			VAR
				percent 		   : longint;
				drawRect		   : Rect;
				myStr			   : Str255;

			BEGIN					   {DrawPercentage}
				{now draw the percentage information}
				SetPort(InfoWind);	   {in this window}

				percent := ((runTim * 100) DIV eTime);
				IF percent >= 100 THEN percent := 99; {just in case}
				IF percent <> lastPerct THEN BEGIN
					SetRect(drawRect,5,60 - 19 {poor man's} ,thePort^.portRect.right,60);
					EraseRect(drawRect);
					MoveTo(5,60);
					NumToString(percent,myStr);
					DrawString(myStr);
					DrawChar('%');
					lastPerct := percent;
				END;				   {IF}
			END;					   {DrawPercentage}

		{------------------------------------------------------------------------------------}

		BEGIN						   {MainEventLoop}

			{first initialize some globals}
			Done := FALSE;			   {we just started!}
			Suspended := FALSE; 	   {as far as we know, we're not suspended}

			WITH ScreenBits.bounds DO
				SetRect(dragRect,4,MenuBarHeight + 4,right - 4,bottom - 4);

			{get initial values for the percentage stuff}
			lastTickCount := TickCount;
			ourTime := lastTickCount;  {prime our lastTime}
			runTime := 0;			   {our total time running}
			elapsedTime := 100; 	   {total time, avoid divide by zero}
			lastPercent := 0;		   {make sure this is drawn}

			cleanUpTicks := lastTickCount; {get the ticks so we know when to compact}

			REPEAT

				DrawRotatingDial(ThePat); {draw a chunk of the dial}

				{now calculate the percent of processor time -- stolen from John Meier}
				WHILE (TickCount - ourTime) < quantum DO; {use up rest of quantum}
				timerTicks := TickCount;
				runTime := runTime + timerTicks - ourTime;
				elapsedTime := elapsedTime + timerTicks - lastTickCount;
				lastTickCount := timerTicks;
				IF elapsedTime > 1000 THEN BEGIN
					runTime := 0;
					elapsedTime := 1;
				END;

				{see if we should compact the heap to get rid of all the free blocks that}
				{writelnWindow creates -- time to be anal ytical?}
				IF NOT Suspended THEN  {only do this if we're in the 4Gnd}
					IF lastTickCount - cleanUpTicks > cleanUpTime THEN BEGIN
						longStuff.long := CompactMem(FreeMem); {coalesce free blocks-- won't
																purge}
						cleanUpTicks := lastTickCount; {reset this guy}
					END;			   {IF}

				{ask for events}
				IF WNEIsImplemented THEN
					hasEvent := WaitNextEvent(everyEvent,MyEvent,YieldTime,WNERgn)
				ELSE BEGIN
					SystemTask; 	   {for drivers}
					hasEvent := GetNextEvent(everyEvent,MyEvent);
				END;				   {ELSE}

				ourTime := TickCount;  {ourTime starts after GetNextEvent}
				DrawPercentage(runTime,elapsedTime,lastPercent); {show the current percentage}

				IF hasEvent THEN
					CASE MyEvent.what OF {which event?}

						mouseDown: BEGIN
							whichPart := FindWindow(MyEvent.where,whichWindow);
						   {the events window gets its own mouseDown events, so let's check...}
							IF whichWindow = gDebugWindowPtr THEN BEGIN
								WWMouseDown(whichPart,MyEvent.where,MyEvent.modifiers);
								WChanged := TRUE; {since WW is a "black box" assume that a
												   mouse-down means that it's grown or moved}
								writeln('mouseDown: Events window');
							END
							ELSE
								CASE whichPart OF

									inDesk:
										writeln('mouseDown: inDesk');

									inMenuBar: BEGIN
										writeln('mouseDown: inMenuBar');
										DoCommand(MenuSelect(MyEvent.where),FALSE);
									END; {inMenuBar}

									inSysWindow: BEGIN
										SystemClick(MyEvent,whichWindow);
										writeln('mouseDown: inSysWindow');
									END; {inSysWindow}
									inContent: BEGIN
										IF whichWindow <> FrontWindow THEN
											SelectWindow(whichWindow);
										writeln('mouseDown: inContent');
									END; {inContent}
									inDrag: BEGIN
										DragWindow(whichWindow,MyEvent.where,dragRect);
										WChanged := TRUE; {to show the configuration needs
														   updating}
										IF whichWindow = InfoWind THEN CalculateWNECursRgns;
										{recalculate the regions if we move InfoWind}
										writeln('mouseDown: inDrag');
									END; {inDrag}
									inGrow:
										writeln('mouseDown: inGrow');
									inGoAway:
										writeln('mouseDown: inGoAway');

								END;   {CASE}
						END;		   {mouseDown}

						keyDown,autoKey: BEGIN
							IF MyEvent.what = keyDown THEN
								writeln('keyDown')
							ELSE
								writeln('autoKey');
							theChar := CHR(BitAnd(MyEvent.message,charCodeMask)); {get the
								char}
							IF BitAnd(MyEvent.modifiers,cmdKey) <> 0 THEN
								DoCommand(MenuKey(theChar),TRUE) {pass it to the command
																  handler}
							ELSE IF WNEIsImplemented THEN BEGIN
								YieldTime := Ord(theChar) - Ord('0'); {so that 0 thru 9 work}
								IF YieldTime < 0 THEN YieldTime := 0; {don't want negatives}
								SetPort(InfoWind);
								InvalRect(InfoWind^.portRect); {generate update event}
							END;	   {IF}
						END;		   {keyDown}

						updateEvt: BEGIN
							SetPort(WindowPtr(MyEvent.message));
							write('update: ');
							IF WindowPtr(MyEvent.message) = InfoWind THEN
								UpdateWindow(WindowPtr(MyEvent.message),'InfoWind')
							ELSE IF WindowPtr(MyEvent.message) = FugitWind THEN
								UpdateWindow(WindowPtr(MyEvent.message),'FugitWind')
							ELSE IF WindowPtr(MyEvent.message) = gDebugWindowPtr THEN BEGIN
								WWUpdateEvent;
								writeln('Events window');
							END 	   {ELSE = gDebugWindowPtr}
							ELSE
								writeln('Unknown window');
						END;		   {updateEvt}

						diskEvt: BEGIN
							longStuff.long := MyEvent.message;
							IF longStuff.HiWrd < 0 THEN {got a bad mount}
								Err := DIBadMount(MyEvent.where,MyEvent.message);
							{we can't really do anything else here that BadMount couldn't do}
							writeln('Disk insert event');
						END;		   {diskEvt}

						activateEvt: BEGIN
							IF BitAnd(MyEvent.modifiers,activeFlag) <> 0 THEN
								write('activate: ')
							ELSE
								write('deactivate: ');
							IF WindowPtr(MyEvent.message) = FugitWind THEN
								writeln('FugitWind')
							ELSE IF WindowPtr(MyEvent.message) = InfoWind THEN
								writeln('InfoWind')
							ELSE IF WindowPtr(MyEvent.message) = gDebugWindowPtr THEN BEGIN
								writeln('Events window');
								WWActivateEvent(MyEvent.modifiers);
							END 	   {ELSE IF}
							ELSE
								writeln('Unknown window');
						END;		   {Activate Event}

						networkEvt:
							writeln('Network Event'); {Juggler doesn't support these}

						driverEvt:
							writeln('Driver Event');

						app1Evt:
							writeln('App1Event');

						app2Evt:
							writeln('App2Event');

						app3Evt:
							writeln('App3Event');

						app4Evt: BEGIN {Juggler uses this for SUSPEND/RESUME and mouse-moved
										events}
							longStuff.long := MyEvent.message;
							IF longStuff.HiByte = MouseMovedMessage THEN BEGIN
								{mouse moved event}
								writeln('MouseMoved');
								FlipCursor; {we got a mouse-moved, flip the cursor}
							END 	   {IF}
							ELSE IF Odd(MyEvent.message) THEN BEGIN
								writeln('RESUME');
								Suspended := FALSE;
								SetPort(InfoWind);
								InvalRect(thePort^.portRect); {force update of the info window}
								IF FrontWindow = gDebugWindowPtr then
									WWActivateEvent(1);

							END 	   {ELSE IF}
							ELSE BEGIN
								writeln('SUSPEND');
								SusPendCount:= 1;
								Suspended := TRUE;
								{we need to deactivate this window, since we are Juggler smart}
								IF FrontWindow = gDebugWindowPtr THEN WWActivateEvent(0);
								SetPort(InfoWind);
								InvalRect(thePort^.portRect); {force update of the info window}
							END;	   {ELSE}
						END;		   {app4Evt}
					END;			   {event.what case}
			UNTIL Done;
		END;						   {MainEventLoop}

	{------------------------------------------------------------------------------------}

	BEGIN							   {PROGRAM}
		Initialize;
		MainEventLoop;
		DisposeRgn(InfoWindRgn);	   {we're all done with it}
		DisposeRgn(AllButInfoWindRgn); {we're all done with it}

  {here we could check to see if any of our windows have been changed, but, since
  this may be running under Juggler, and someone could go into the Finder and
  delete our configuration file while we are running, we'll just always write
  the configuration data}

		{IF WChanged THEN}
		WriteConfigInfo;

		writeln;
		writeln('Bye bye');
	END.
